﻿/**
* CRL
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using CRL.Core;
using System.Reflection;
using CRL;
using System.Collections.Concurrent;

namespace CRL.LambdaQuery
{
    public partial class ExpressionVisitor
    {
        DbContextInner dbContext
        {
            get
            {
                return lambdaQueryBase.__DbContext;
            }
        }
        DBAdapter.DBAdapterBase __DBAdapter
        {
            get
            {
                return lambdaQueryBase.__DBAdapter;
            }
        }
        ///// <summary>
        ///// 字段前辍 t1.
        ///// </summary>
        //Dictionary<Type, string> Prefixs
        //{
        //    get
        //    {
        //        return lambdaQueryBase.__Prefixs;
        //    }
        //}

        LambdaQueryBase lambdaQueryBase;
        public ExpressionVisitor(LambdaQueryBase _lambdaQueryBase)
        {
            lambdaQueryBase = _lambdaQueryBase;
        }

        string FormatFieldPrefix(Type type,string parameterName, string fieldName)
        {
            //if (!Base.CheckIfAnonymousType(type))
            //{
            //    parameterName = "";
            //}
            return lambdaQueryBase.GetPrefix(type, parameterName: parameterName) + fieldName;
        }
        /// <summary>
        /// 处理后的查询参数
        /// </summary>
        internal List<Tuple<string, object>> QueryParames = new List<Tuple<string, object>>();
        int parIndex
        {
            get
            {
                return dbContext.parIndex;
            }
            set
            {
                dbContext.parIndex = value;
            }
        }
        //static string[] parameDic = null;
        static ConcurrentDictionary<DBAccess.DBType, string[]> parameDicList = new ConcurrentDictionary<DBAccess.DBType, string[]>();
        CRLExpression.CRLExpression DealParame(CRLExpression.CRLExpression par1, string typeStr)
        {
            var parValue = par1.Data;
            //typeStr2 = typeStr;
            //todo 非关系型数据库不参数化
            if (dbContext.DataBaseArchitecture == DataBaseArchitecture.NotRelation)
            {
                return par1;
            }
            var a = parameDicList.TryGetValue(__DBAdapter.DBType, out string[] parameDic);
            if (!a)
            {
                parameDic = new string[5000];
                for (int i = 0; i < 5000; i++)
                {
                    parameDic[i] = __DBAdapter.GetParamName("p", i);
                }
                parameDicList.TryAdd(__DBAdapter.DBType, parameDic);
            }
            if (parIndex >= 5000)
            {
                //MSSQL 参数最多2800
                throw new Exception("参数计数超过了5000,请确认数据访问对象没有被静态化" + parIndex);
            }
            switch (par1.Type)
            {
                case CRLExpression.CRLExpressionType.Value:
                    #region value
                    if (par1.Data == null)
                    {
                        parValue = __DBAdapter.IsNotFormat(typeStr != "=") + "null";
                    }
                    else
                    {
                        if(SettingConfig.FieldParameName)
                        {
                            par1.DataParamed = parValue.ToString();
                            return par1;//参数名按字段名
                        }
                        var _par = parameDic[parIndex];
                        AddParame(_par, parValue);
                        parValue = _par;
                        parIndex += 1;
                    }
                    #endregion
                    break;
                case CRLExpression.CRLExpressionType.MethodCall:
                    #region method
                    var method = par1.Data as CRLExpression.MethodCallObj;

                    var dic = MethodAnalyze.GetMethos(__DBAdapter);
                    if (!dic.ContainsKey(method.MethodName))
                    {
                        throw new Exception("LambdaQuery不支持扩展方法" + method.MemberQueryName + "." + method.MethodName);
                    }
                    int newParIndex = parIndex;
                    parValue = dic[method.MethodName](method, ref newParIndex, AddParame);
                    parIndex = newParIndex;
                    #endregion
                    break;
            }
            par1.DataParamed = parValue.ToString();
            return par1;
        }

        static ExpressionType[] binaryTypes = new ExpressionType[] { ExpressionType.Equal, ExpressionType.GreaterThan, ExpressionType.GreaterThanOrEqual, ExpressionType.LessThan, ExpressionType.LessThanOrEqual, ExpressionType.NotEqual };
        public string DealCRLExpression(Expression exp, CRLExpression.CRLExpression b, string typeStr, out bool isNullValue, bool first = false)
        {
            isNullValue = false;
            switch (b.Type)
            {
                case CRLExpression.CRLExpressionType.Name:
                    return FormatFieldPrefix(b.MemberType, b.typeParameterName, b.Data.ToString());
                case CRLExpression.CRLExpressionType.Binary:
                    return b.Data.ToString();
                default:
                    var valExp = (b.IsConstantValue || first) ? b : RouteExpressionHandler(exp);
                    isNullValue = valExp.Data == null;
                    var par2 = DealParame(valExp, typeStr);
                    //对运算增加括号以区分优先级
                    if (b.Type == CRLExpression.CRLExpressionType.Tree)
                    {
                        return $"({par2.DataParamed})";
                    }
                    return par2.DataParamed;
            }
        }

        /// <summary>
        /// 解析表达式
        /// </summary>
        /// <param name="exp"></param>
        /// <param name="nodeType"></param>
        /// <param name="firstLevel">是否首次调用,来用修正bool一元运算</param>
        /// <returns></returns>
        public CRLExpression.CRLExpression RouteExpressionHandler(Expression exp, ExpressionType? nodeType = null, bool firstLevel = false)
        {
            if (exp is BinaryExpression)
            {
                //like a.Name??str
                BinaryExpression be = (BinaryExpression)exp;
                if (be.NodeType == ExpressionType.Coalesce)
                {
                    var par1 = new CRLExpression.CRLExpression();
                    par1.Type = CRLExpression.CRLExpressionType.MethodCall;
                    var member = be.Left as MemberExpression;
                    if (member == null)
                    {
                        throw new Exception(be.Left + "不为MemberExpression");
                    }
                    var args = RouteExpressionHandler(be.Right);
                    par1.Data = new CRLExpression.MethodCallObj() { MemberName = member.Member.Name, MethodName = "IsNull", Args = new List<object>() { args.Data }, MemberQueryName= member.Member.Name };
                    return DealParame(par1, "");
                }
                return BinaryExpressionHandler(be.Left, be.Right, be.NodeType);
            }
            if (exp is MemberExpression)
            {
                return MemberExpressionHandler(exp, nodeType, firstLevel);
            }
            else if (exp is ConstantExpression)
            {
                return ConstantExpressionHandler(exp, nodeType, firstLevel);
            }
            else if (exp is MethodCallExpression)
            {
                return MethodCallExpressionHandler(exp, nodeType, firstLevel);
            }
            else if (exp is UnaryExpression)
            {
                return UnaryExpressionHandler(exp, nodeType, firstLevel);
            }
            else if (exp is NewArrayExpression)
            {
                return NewArrayExpressionHandler(exp, nodeType, firstLevel);
            }
            else if (exp is ConditionalExpression)
            {
                return ConditionalExpressionHandler(exp, nodeType, firstLevel);
            }
            else
            {
                throw new Exception("不支持此语法解析:" + exp);
            }
        }
        public void AddParame(string name, object value)
        {
            QueryParames.Add(new Tuple<string, object>(name, value));
            //parIndex += 1;
        }
        static Dictionary<ExpressionType, string> expressionTypeCache = new Dictionary<ExpressionType, string>() {
            { ExpressionType.And, "&" } ,{ ExpressionType.AndAlso, " AND " },
            {ExpressionType.Equal, "=" },{ ExpressionType.GreaterThan, ">"},{ExpressionType.GreaterThanOrEqual, ">=" },{ExpressionType.LessThan, "<" },{ ExpressionType.LessThanOrEqual, "<="},{ ExpressionType.NotEqual, "<>"},{ ExpressionType.Or, "|"},{ ExpressionType.OrElse, " OR "},{ ExpressionType.Add, "+"},{ ExpressionType.Subtract, "-"},{ ExpressionType.SubtractChecked, "-"},{ ExpressionType.Multiply, "*"},{ ExpressionType.MultiplyChecked,"*"},{ ExpressionType.Divide,"/"},{ ExpressionType.Not, "!="}
        };
        //static object lockObj = new object();
        public static string ExpressionTypeCast(ExpressionType expType)
        {
            string type;
            var a = expressionTypeCache.TryGetValue(expType, out type);
            if (a)
            {
                return type;
            }
            throw new InvalidCastException("不支持的运算符" + expType);

        }
        object GetParameExpressionValue(Expression expression, out bool isConstant)
        {
            isConstant = false;
            //只能处理常量
            if (expression is ConstantExpression)
            {
                isConstant = true;
                ConstantExpression cExp = (ConstantExpression)expression;
                return cExp.Value;
            }
            else if (expression is MemberExpression)//按属性访问
            {
                var m = expression as MemberExpression;
                var typeParameterName = (m.Expression as ParameterExpression)?.Name;
                if (m.Expression != null)
                {
                    if (m.Expression.NodeType == ExpressionType.Parameter)
                    {
                        string name = m.Member.Name;
                        var filed2 = TypeCache.GetProperties(m.Expression.Type, true)[name];
                        return new ExpressionValueObj { Value = FormatFieldPrefix(m.Expression.Type, typeParameterName, __DBAdapter.FieldNameFormat(filed2)), IsMember = true, member = m.Member };
                    }
                    else
                    {
                        return ConstantValueVisitor.GetMemberExpressionValue(m, out isConstant);
                    }
                }
                return ConstantValueVisitor.GetMemberExpressionValue(m, out isConstant);
            }
            //按编译
            return Expression.Lambda(expression).Compile().DynamicInvoke();
        }
    }
    internal class ExpressionValueObj
    {
        public MemberInfo member;
        public object Value;
        public bool IsMember;
        public override string ToString()
        {
            return Value + "";
        }
    }
}
